package home.project;

import home.project.SpriteSheet.SpriteFrameLink;
import openfl.display.Graphics;
import openfl.display.Sprite;
import openfl.display.BitmapData;
import openfl.display.Bitmap;
import openfl.display.Tilesheet;
import openfl.geom.Point;
import openfl.geom.Rectangle;
import openfl.geom.Matrix;
import openfl.Assets;


/**
 * ...
 * @author an.vuongngocduy
 */

class SpriteModule 
{ 
	public var image:Int;		
	public var name:String;	
	public var region:Rectangle; 
	public function new(){}
}

class SpriteModuleLink
{
	public var id:Int;
	public var module:Int;
	public var placement:Point;
	public var transform:Matrix;
	public function new(){}
}

class SpriteFrame
{
	public var name:String;
	public var rect:Rectangle;
	public var modules:Array<SpriteModuleLink>;
	public function new(){}
}
 
class SpriteFrameLink
{
	public var id:Int;
	public var frame:Int;
	public var bbox:Rectangle;
	public var placement:Point;
	public function new(){}
}

class SpriteAnim 
{
	public var name:String;
	public var frames:Array<SpriteFrameLink>;
	public function new(){}
}

class SpriteSheet
{
	private var __images:Array<String>;
	private var __modules:Array<SpriteModule>;
	private var __frames:Array<SpriteFrame>;
	private var __anims:Array<SpriteAnim>;

	private var __name:String;
	private var __isLoop:Bool;
	private var __curAnim:Int;
	private var __curAnimFrame:Int;
	private var __curFps:Int;
	private var __lastTime:Float;
	
	public function new() 
	{
		//! Do nothing
	}
		
	public static function load(p_path:String):SpriteSheet
	{
		var spr:SpriteSheet = new SpriteSheet();
		spr.__curFps = 10;
		spr.__curAnim = 0;
		spr.__curAnimFrame = 0;
		spr.__lastTime = 0.0;
		spr.__isLoop = true;	
		spr.__images = new Array<String>();
		spr.__modules = new Array<SpriteModule>();
		spr.__frames = new Array<SpriteFrame>();
		spr.__anims = new Array<SpriteAnim>();
		var root:Xml = Xml.parse(Assets.getText(p_path));
		
		var sprNode:Xml = root.firstElement();
		
		spr.__name = sprNode.get("name");
		
		for (node in sprNode.elements())
		{
			if (node.nodeName == "Images")
			{
				for (img in node.elements())
				{
					spr.__images.push(img.get("path"));
				}
			}
			else if (node.nodeName == "Modules")
			{
				for (mod in node.elements())
				{
					var sm:SpriteModule = new SpriteModule();
					
					sm.image = Std.parseInt(mod.get("ImageId"));
					sm.name = mod.get("comment");
					sm.region = new Rectangle();
					sm.region.x = Std.parseInt(mod.get("x"));
					sm.region.y = Std.parseInt(mod.get("y"));
					sm.region.width = Std.parseInt(mod.get("width"));
					sm.region.height = Std.parseInt(mod.get("height"));
									
					spr.__modules.push(sm);
				}
			}
			else if (node.nodeName == "Frames")
			{
				for (fr in node.elements())
				{
					var sf:SpriteFrame = new SpriteFrame();

					sf.name = fr.get("name");
					sf.modules = new Array<SpriteModuleLink>();
					
					for (node2 in fr.elements())
					{
						var mdl:SpriteModuleLink = new SpriteModuleLink();
						mdl.module = Std.parseInt(node2.get("moduleId"));
						mdl.placement = new Point(Std.parseInt(node2.get("x")), Std.parseInt(node2.get("y")));
						sf.modules.push(mdl);
					}
					
					spr.__frames.push(sf);
				}
			}
			else if (node.nodeName == "Animations")
			{
				for (an in node.elements())
				{
					var sa:SpriteAnim = new SpriteAnim();
					
					sa.name = an.get("name");
					sa.frames = new Array<SpriteFrameLink>();
		
					for (node2 in an.elements())
					{
						var frl:SpriteFrameLink = new SpriteFrameLink();
						frl.frame = Std.parseInt(node2.get("frameId"));
						frl.bbox = new Rectangle(Std.parseInt(node2.get("x")), Std.parseInt(node2.get("y")),
												Std.parseInt(node2.get("width")), Std.parseInt(node2.get("height")));
						frl.placement = new Point(Std.parseInt(node2.get("x")), Std.parseInt(node2.get("y")));
						sa.frames.push(frl);
					}
					spr.__anims.push(sa);
				}
			}
		}
		return spr;
	}
	
	public function setCurrentAnimation(p_idx:Int):Void
	{
		if (p_idx >= __anims.length || p_idx < 0 || p_idx == __curAnim) return;
		__curAnim = p_idx;
		__curAnimFrame = 0;
	}
	
	public function getCurrentAnimation():Int
	{
		return __curAnim;
	}
	
	public function getCurrentFrame():Int
	{
		return __anims[__curAnim].frames[__curAnimFrame].frame;
	}
	
	public function getCurrentBBox():Rectangle
	{
		return return __anims[__curAnim].frames[__curAnimFrame].bbox;
	}
	
	public function enableLoop(p_enabled:Bool):Void
	{
		__isLoop = p_enabled;
	}
	
	public function draw(p_g:Graphics, p_x:Int, p_y:Int):Void
	{
		drawFrame(p_g,  __anims[__curAnim].frames[__curAnimFrame].frame, p_x, p_y);
	}
	
	public function drawModule(p_g:Graphics, p_moduleIdx:Int, p_x:Int, p_y:Int, p_transform:Matrix = null):Void
	{
		var pixels:BitmapData = Assets.getBitmapData("img/" + __images[__modules[p_moduleIdx].image]);
		
		var mat:Matrix = new Matrix();
		mat.translate(p_x - __modules[p_moduleIdx].region.x, p_y - __modules[p_moduleIdx].region.y);
		if(p_transform != null)
			p_g.beginBitmapFill(pixels, p_transform);
		else
			p_g.beginBitmapFill(pixels, mat, false);
		p_g.drawRect(p_x, p_y, __modules[p_moduleIdx].region.width, __modules[p_moduleIdx].region.height);
		p_g.endFill();
	}
	
	public function drawFrame(p_g:Graphics, p_frameIdx:Int, p_x:Int, p_y:Int):Void
	{
		var count:Int = 0;	
		while (count < __frames[p_frameIdx].modules.length)
		{		
			var moLink:SpriteModuleLink = __frames[p_frameIdx].modules[count];
			var local_x:Int = p_x + Std.int(moLink.placement.x);
			var local_y:Int = p_y + Std.int(moLink.placement.y);
			drawModule(p_g, moLink.module, local_x, local_y, moLink.transform);
			count++;
		}
	}
	
	public function step():Void
	{
		var frame_delay:Float = 1000.0 / __curFps;
		__lastTime += Globals.sElapsedTime;
		var frame_step:Int = Std.int( __lastTime/ frame_delay);
		
		if (frame_step > 0)
		{
			__curAnimFrame += frame_step;
			__lastTime -= frame_step * frame_delay;
		}
		
		if (__curAnimFrame >= __anims[__curAnim].frames.length)
			__curAnimFrame = 0;
	}
}